<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Regulex Vue：JavaScript Regular Expression Visualizer</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div id="app">
        <h1>Regulex <em>JavaScript Regular Expression Visualizer (Vue版本)</em></h1>

        <div class="input-container">
            <div class="regex-input code">
                <table>
                    <tr>
                        <td style="width:1em">/</td>
                        <td style="width:auto">
                            <input
                                v-model="regexInput"
                                class="input"
                                @keyup="onKeyup"
                                @keydown="onEnter"
                                @paste="onPaste"
                                placeholder="输入正则表达式"
                            />
                        </td>
                        <td style="width:1em">/</td>
                        <td style="width:3em">{{ flags }}</td>
                    </tr>
                </table>
            </div>

            <button class="btn" @click="visualize">Visualize</button>
            <button class="btn" @click="exportImage">Export Image</button>
            <button class="btn" @click="embedCode">Embed On My Site!</button>

            <label class="flag-label">
                <input type="checkbox" v-model="flagI" @change="onFlagChange"/>IgnoreCase
            </label>
            <label class="flag-label">
                <input type="checkbox" v-model="flagM" @change="onFlagChange"/>Multiline
            </label>
            <label class="flag-label">
                <input type="checkbox" v-model="flagG" @change="onFlagChange"/>GlobalMatch
            </label>
        </div>

        <p v-if="errorMessage" class="error-box code">{{ errorMessage }}</p>

        <div ref="graphContainer" class="graph-container code"></div>
    </div>

    <script src="../assets/regulex.js"></script>
    <script>
        const { createApp, ref, reactive, computed, onMounted, nextTick } = Vue;

        // 获取 regulex 依赖的函数
        function getRegulexDependencies() {
            const regulex = require('regulex');
                return {
                    parse: regulex.parse,
                    visualize: regulex.visualize,
                    Raphael: regulex.Raphael,
                    Kit: regulex.Kit
                };
        }

        createApp({
            setup() {
                const regexInput = ref('^(a|b)*?$');
                const flagI = ref(false);
                const flagM = ref(false);
                const flagG = ref(false);
                const errorMessage = ref('');
                const graphContainer = ref(null);
                const paper = ref(null);
                const regulexDeps = ref(null);
                const params = reactive({
                    embed: false,
                    re: '',
                    highlight: true,
                    flags: '',
                    debug: false,
                    cmd: ''
                });

                // 计算属性
                const flags = computed(() => {
                    let result = '';
                    if (flagI.value) result += 'i';
                    if (flagM.value) result += 'm';
                    if (flagG.value) result += 'g';
                    return result;
                });

                // 工具函数
                function trim(s) {
                    return s.replace(/^\s+/, '').replace(/\s+$/, '');
                }

                function getParams() {
                    const hash = location.hash;
                    if (!hash || hash.length < 2) {
                        return { embed: false, re: "", highlight: true, flags: '' };
                    }

                    const paramsStr = hash.slice(2);
                    const paramsObj = paramsStr.split("&").reduce(function (p, a) {
                        const parts = a.split("=");
                        p[parts[0]] = parts[1];
                        return p;
                    }, {});

                    return {
                        embed: paramsObj.embed === 'true',
                        flags: paramsObj.flags || '',
                        re: paramsObj.re ? trim(decodeURIComponent(paramsObj.re)) : '',
                        debug: paramsObj.debug === 'true',
                        cmd: paramsObj.cmd || ''
                    };
                }

                function serializeHash() {
                    const re = trim(regexInput.value);
                    const flagsStr = flags.value;
                    return "#!" +
                        (params.debug ? "debug=true&" : "") +
                        (params.cmd ? "cmd=" + params.cmd + "&" : "") +
                        (params.embed ? "embed=true&" : "") +
                        "flags=" + flagsStr + "&re=" + encodeURIComponent(re);
                }

                function changeHash() {
                    location.hash = serializeHash();
                }

                function hideError() {
                    errorMessage.value = '';
                }

                function showError(re, err) {
                    let msg = ["Error:" + err.message, ""];
                    if (typeof err.lastIndex === 'number') {
                        msg.push(re);
                        msg.push('-'.repeat(err.lastIndex) + "^");
                    }
                    errorMessage.value = msg.join("\n");
                }

                // 核心功能函数 - 修改为支持多种依赖获取方式
                function visualize(skipError = false) {
                    if (!regulexDeps.value) {
                        console.error('Regulex dependencies not available');
                        return false;
                    }

                    if (!graphContainer.value) {
                        console.error('Graph container not available');
                        return false;
                    }

                    const re = trim(regexInput.value);
                    changeHash();
                    hideError();
                    try {
                        // 只在第一次创建 paper，后续重复使用
                        if (!paper.value) {
                            paper.value = regulexDeps.value.Raphael(graphContainer.value, 10, 10);
                        }

                        // 解析正则表达式
                        const ast = regulexDeps.value.parse(re);

                        // 可视化 - regulex 的 visualize 函数内部会调用 paper.clear()
                        regulexDeps.value.visualize(ast, flags.value, paper.value);
                        return true;
                    } catch (e) {
                        if (!skipError) {
                            showError(re, e);
                        }
                        return false;
                    }
                }

                function onFlagChange() {
                    visualize();
                    changeHash();
                }

                function onKeyup(e) {
                    if (e.keyCode === 13) return; // Enter
                    clearTimeout(window.onKeyupTid);
                    window.onKeyupTid = setTimeout(() => {
                        visualize(true);
                    }, 100);
                }

                function onEnter(e) {
                    if (e.keyCode === 13) {
                        e.preventDefault();
                        e.stopPropagation();
                        visualize();
                    }
                }

                function onPaste(e) {
                    setTimeout(() => {
                        const content = trim(e.clipboardData.getData('text'));
                        if (content[0] === '/' && /\/[img]*$/.test(content)) {
                            const endIndex = content.lastIndexOf('/');
                            const flagsStr = content.slice(endIndex + 1);
                            const regexStr = content.slice(1, endIndex);

                            // 设置标志
                            flagI.value = flagsStr.includes('i');
                            flagM.value = flagsStr.includes('m');
                            flagG.value = flagsStr.includes('g');

                            // 设置正则表达式
                            regexInput.value = regexStr;
                        }
                        visualize();
                    }, 50);
                }

                function exportImage() {
                    const newParams = { ...params };
                    newParams.cmd = 'export';
                    const hash = serializeHash();
                    window.open(location.href.split('#!')[0] + hash, "_blank");
                }

                function embedCode() {
                    if (!visualize()) return false;

                    const src = location.href;
                    const i = src.indexOf('#');
                    const baseSrc = i > 0 ? src.slice(0, i) : src;
                    changeHash();
                    const re = trim(regexInput.value);
                    const html = `<iframe frameborder="0" width="400" height="300" src="${baseSrc}#!embed=true&flags=${flags.value}&re=${encodeURIComponent(re)}"></iframe>`;
                    window.prompt("复制HTML代码:", html);
                }

                function dragGraph(container) {
                    if (!container) return;

                    container.addEventListener('mousedown', startMove);

                    function startMove(e) {
                        clearSelect();
                        let x = e.clientX, y = e.clientY;
                        container.addEventListener('mousemove', onMove);

                        document.addEventListener('mouseup', unbind, true);
                        window.addEventListener('mouseup', unbind, true);

                        function unbind(e) {
                            container.removeEventListener('mousemove', onMove);
                            document.removeEventListener('mouseup', unbind, true);
                            window.removeEventListener('mouseup', unbind, true);
                        }

                        function onMove(e) {
                            let dx = x - e.clientX, dy = y - e.clientY;
                            if (dx > 0 && container.scrollWidth - container.scrollLeft - container.clientWidth < 2
                                || dx < 0 && container.scrollLeft < 1) {
                                document.documentElement.scrollLeft += dx;
                                document.body.scrollLeft += dx;
                            } else {
                                container.scrollLeft += dx;
                            }
                            if (dy > 0 && container.scrollHeight - container.scrollTop - container.clientHeight < 2
                                || dy < 0 && container.scrollTop < 1) {
                                document.documentElement.scrollTop += dy;
                                document.body.scrollTop += dy;
                            } else {
                                container.scrollTop += dy;
                            }
                            x = e.clientX;
                            y = e.clientY;
                        }
                    }
                }

                function clearSelect() {
                    if (window.getSelection) {
                        if (window.getSelection().empty) {
                            window.getSelection().empty();
                        } else if (window.getSelection().removeAllRanges) {
                            window.getSelection().removeAllRanges();
                        }
                    } else if (document.selection) {
                        document.selection.empty();
                    }
                }

                // 初始化
                onMounted(() => {
                    // 获取 regulex 依赖
                    regulexDeps.value = getRegulexDependencies();

                    if (!regulexDeps.value) {
                        console.error('Failed to load Regulex dependencies');
                        errorMessage.value = 'Error: Failed to load Regulex dependencies';
                        return;
                    }

                    // 获取URL参数
                    const urlParams = getParams();
                    Object.assign(params, urlParams);

                    // 设置初始值
                    if (params.flags) {
                        flagI.value = params.flags.includes('i');
                        flagM.value = params.flags.includes('m');
                        flagG.value = params.flags.includes('g');
                    }

                    if (params.re) {
                        regexInput.value = params.re;
                    }

                    // 使用 nextTick 确保 DOM 渲染完成后再初始化
                    nextTick(() => {
                        // 初始化可视化
                        visualize();

                        // 初始化拖拽功能
                        if (graphContainer.value) {
                            dragGraph(graphContainer.value);
                        }
                    });
                });

                return {
                    regexInput,
                    flagI,
                    flagM,
                    flagG,
                    flags,
                    errorMessage,
                    graphContainer,
                    visualize,
                    onFlagChange,
                    onKeyup,
                    onEnter,
                    onPaste,
                    exportImage,
                    embedCode
                };
            }
        }).mount('#app');
    </script>
</body>
</html>